<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
// JS普通函数定义泛型与箭头函数定义泛型
// 1.普通函数定义泛型#

// const fn1 = function aa<T> (a:T):T { return a }
// console.log(fn1<string>('aaaaaaa'))

// 2.箭头函数定义泛型#
// const foo1 = <T, >(x: T): T => x
// const foo2: <T>(x: T) => T = x => x;foo2: <T>(x: T) => T 和 x => x;
// const foo3 = <T extends {name:'666'}>(x: T): T => x       
// 相同之处：
// 泛型定义都是在（）之间用‘<>’括起来的，使用的时候之间在需要用的地方之间声明变量，然后冒号注明该类型，例如var a:T = 
// 区别之处：
// 箭头函数定义有两种：
// 1.<T, >,需要逗号分割，()：T再次注明该泛型,加个逗号是为了和jsx语法做区分，jsx语法就是在写js语法是可以写html标签在逻辑里，含<>
// 2.<T>无需逗号分割，() =>T再次注明该泛型
// const fn2 = <T>(a: T): T => a

// const fn2:<T>(a:T)=>T =a=>a
// console.log('箭头函数返回值：'+fn2<number>(5555))

// type与interface(是一种描述对象或函数的东西)继承
// https://cloud.tencent.com/developer/article/1411764
// interface item {
//   add: string
// }
type item = number
// interface diyType extends item {
//   id: string
//   age: number
//   arr: boolean[]
//   obj: { [key: string]: { name1: string, name2?: number } }
// }
// type diyType = {
//   id:string
//   age:number
//   arr:boolean[]
//   obj:{[key:string]:{name1:string,name2?:number}}
// }&{
//   add:string
// }
// const fn = function aa<T>(a: T): T { return a }
// console.log(fn<diyType>({
//   id: 'id', age: 12, arr: [true], obj: {
//     'key': { name1: 'string' },
//     'key1': { name1: 'string', name2: 888 }
//   }, add: 'asfad'
// }))

// // 扩展：
// interface allObj<B, C> {
//   title: string
//   isLock: B
//   comments: C[]
// }

// type CommentType = {
//   content: string
//   author?: string
// }
// const hd: allObj<boolean, CommentType> = {
//   title: '标题',
//   isLock: true,
//   comments: [{
//     content: "content",
//     author: 'author'
//   }]
// }

// switchRadio(trigger:boolean):void        //注意写法，void表示函数没有返回值

//ts高级类型，类型断言，类型保护（typeof,instanceof）

// implements不咋懂(instanceof类型保护里面有用到案例)

// 类型断言
// let someValue: any = 'this is string'
// let strLength:number = (someValue as string).length
// let strLength: number = (<string>someValue).length
// https://www.tslang.cn/docs/handbook/advanced-types.html


// 浅析TypeScript不可变量的实现方法（const和readonly）的区别（https://www.cnblogs.com/goloving/p/15412110.html）

// （1）const 用于变量， readonly 用于属性
// （2）const 在运行时检查， readonly 在编译时检查
// （3）const 声明的变量不得改变值，这意味着，const 一旦声明变量，就必须立即初始化，不能留到以后赋值；
// 　　readonly 修饰的属性能确保自身不能修改属性，但是当你把这个属性交给其它并没有这种保证的使用者（允许出于类型兼容性的原因），
//    他们能改变（如下）
// const foo: {
//   readonly bar: number;
// } = {
//   bar: 123
// };
// function iMutateFoo(foo: { bar: number }) {
//   foo.bar = 456;
// }
// iMutateFoo(foo);//给形参赋值(有readonly修饰的属性赋值给了形参，可以修改了)
// console.log(foo.bar,101); // 456


const objConst = {a:1,b:2} as const;//断言是不可变量
objConst.a = 333;
// const原理：保证的不是变量的值不得改动，而是变量指向的那个内存地址不得改动（堆栈都有地址概念）

// 枚举和常量枚举的区别以及关于typescript中枚举的相关知识（不理解）

const handleClick = (): void => {
  window.location.href = "https://www.tslang.cn/docs/handbook/basic-types.html"
}


//当数组包对象如何写泛型
type tableDataType = {
  date: string,
  name: string,
  state: string,
  city: string,
  address: string,
  zip: string
}

type tableDataType1 = {
  date: string,
  name: string,
  state: string,
  city: string,
  address: string,
  zip: string
}[]

const tableData: tableDataType1 = [
  {
    date: '广泛的类型,使用前不确定',
    name: '自定义类型,里面不需要,',
    state: '联合类型...',
    city: '<>和as',
    address: '继承(1个)和提取(多个)',
    zip: '(4个类型)-(原型链上找)',
  }
]

// ts如何定义数组中嵌套对象的类型
// https://blog.csdn.net/qq_40137978/article/details/126289709





// 课后习题
type Filter = {
    
}

// let filter: Filter = (array, f) => ......

// function filter<T>(array: T[], f: (item: T) => boolean): T[]{
//   return []
// }


//函数重载（根据传入不同的参数而返回不同类型的数据是很常见的）
// 联合类型也可以做到参数类型切换，但是当参数关联就无法搞定了
let suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: { suit: string; card: number; }[]): number;
function pickCard(x: number): { suit: string; card: number; };
// 下面不是重载列表的一部分，只有上面两个重载：一个接受对象列表返回数字，另一个接受数字返回对象
// 实际实现，它是函数体需要处理的所有情况的真实表示
function pickCard(x): any {
  if (typeof x == 'object') {
    let pickCard = Math.floor(Math.random() * x.length);
    return pickCard;
  } else if (typeof x == 'number') {
    let pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13 };
  }
}

// 调用时重载的函数会进行正确的类型检查
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard3 = myDeck[pickCard(myDeck)];
console.log(myDeck[pickCard(myDeck)], pickCard(myDeck), 999);
console.log("card: " + pickedCard3.card + " of " + pickedCard3.suit);

let pickedCard2 = pickCard(15);
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);


// TS中可以把所有参数收集到一个变量里：用...表示 剩余参数会被当做个数不限的可选参数，可以是0到多个
// function buildOtherName(firstName: string, ...restOfName: string[]){
//   return firstName + ' ' + restOfName.join(' ');
// }
// let ohters = buildOtherName('Bob', 'Admas', 'jjzhang','hahaa', 'kdddd');


</script>

<template>
  <h1>TS理解</h1>
  <!-- vue3 element-plus table 数据显示不出来现象（chrome72版32位显示不出来） -->
  <el-table :data="tableData" style="width: 100%">
    <el-table-column fixed prop="date" label="泛型" width="200" />
    <el-table-column prop="name" label="interface与type" width="200" />
    <el-table-column prop="state" label="高级类型" width="120" />
    <el-table-column prop="city" label="类型断言" width="120" />
    <el-table-column prop="address" label="extends与implements" width="200" />
    <el-table-column prop="zip" label="类型保护(typeof与instanceof)" width="300" />
    <el-table-column fixed="right" label="TS掌握(10%)" width="120">
      <template #default>
        <el-button link type="primary" size="small" @click="handleClick">彩笔去看</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<style scoped>

</style>